package cn.bitkit.tools.common;

import java.io.BufferedReader;
import java.io.Flushable;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.util.StringJoiner;

import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;

/**
 * @author changbo
 */
@Slf4j
public class IOUtil {

    public static final int BUFF_LENGTH = 1024*8;

    public static byte[] readBytes(InputStream is){
        return readString(is).getBytes();
    }

    public static byte[] readBytes(BufferedReader reader){
        return readString(reader).getBytes();
    }

    public static String readString(InputStream is){
        return readString(new BufferedReader(new InputStreamReader(is)));
    }

    @SneakyThrows
    public static String readString(BufferedReader reader){
        StringJoiner join = new StringJoiner("\n", "", "\n");
        String buf = null;
        while ((buf = reader.readLine()) != null) {
            join.add(buf);
        }
        return join.toString();
    }

    @SneakyThrows
    public static void write(byte[] bytes, OutputStream out){
        out.write(bytes, 0, bytes.length);
        out.flush();
    }

    @SneakyThrows
    public static void write(InputStream in, OutputStream out){
        int read;
        byte[] buffer = new byte[BUFF_LENGTH];
        while ((read = in.read(buffer)) != -1) {
            out.write(buffer, 0, read);
        }
        out.flush();
        out.close();
    }

    @SneakyThrows
    public static void write(InputStream in, FileChannel out) {
        byte[] buff = new byte[BUFF_LENGTH];
        int read = 0;
        while((read = in.read(buff)) > 0) {
            ByteBuffer buf = ByteBuffer.wrap(buff, 0, read);
            out.write(buf);
        }
    }

    @SneakyThrows
    public static void write(FileChannel in, OutputStream out) {
        ByteBuffer buf = ByteBuffer.allocate(BUFF_LENGTH) ;
        byte[] buff = new byte[BUFF_LENGTH];
        int read = 0;
        while((read = in.read(buf)) > 0) {
            buf.flip();
            buf.get(buff, 0, read);
            buf.clear();
            out.write(buff, 0, read);
        }
    }

    public static void close(AutoCloseable... acList) {
        if(acList == null) {
            return;
        }
        for(AutoCloseable ac : acList){
            try {
                if(ac != null){
                    ac.close();
                }
            } catch (Exception e) {
                log.error("", e);
            }
        }
    }

    public static void flush(Flushable... fList) {
        if(fList == null) {
            return;
        }
        for(Flushable ac : fList){
            try {
                if(ac != null){
                    ac.flush();
                }
            } catch (Exception e) {
                log.error("", e);
            }
        }
    }
}
